#include <benchmark/benchmark.h>
#include <sys/syscall.h>
#include <string.h>
#include <signal.h>
#include <sys/resource.h>
#include <stdio.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include <sys/utsname.h>
#include "util.h"

using namespace std;

static void Bm_function_Syscall_getpid(benchmark::State &state)
{
	pid_t pid;
	for (auto _ : state)
	{
		pid = syscall(SYS_getpid);
		benchmark::DoNotOptimize(pid);
	}
}

static void Bm_function_Syscall_gettid(benchmark::State &state)
{
	pid_t pid;
	for (auto _ : state)
	{
		pid = syscall(SYS_gettid);
		benchmark::DoNotOptimize(pid);
	}
}

static void Bm_function_Syscall_gettimeofday(benchmark::State &state)
{
	struct timeval tv;
	for (auto _ : state)
	{
		benchmark::DoNotOptimize(syscall(SYS_gettimeofday, &tv, NULL));
	}
}

static void Bm_function_Syscall_write(benchmark::State &state)
{
	for (auto _ : state)
	{
		benchmark::DoNotOptimize(syscall(SYS_write, STDOUT_FILENO, "Bad Mind", 8));
	}
}

static void Bm_function_Syscall_read(benchmark::State &state)
{
	char buf[10];
	int fd = open("/dev/zero", O_RDONLY);
	if (fd == -1)
	{
		perror("syscall read");
		exit(EXIT_FAILURE);
	}
	for (auto _ : state)
	{
		ssize_t ret = syscall(SYS_read, fd, buf, 10);
		if (ret < 0)
		{
			perror("syscall read");
			exit(EXIT_FAILURE);
		}
		benchmark::DoNotOptimize(ret);
	}
}


static void Bm_function_Syscall_fcntl(benchmark::State &state)
{
	long int ret;
	int fd = open("/dev/zero", O_RDONLY);
	if (fd == -1)
	{
		perror("syscall_fcntl open");
		exit(EXIT_FAILURE);
	}
	for (auto _ : state)
	{
		ret = syscall(SYS_fcntl, fd, F_GETFL);
		if (ret == -1)
		{
			perror("syscall_fcntl fail");
			exit(EXIT_FAILURE);
		}
		benchmark::DoNotOptimize(ret);
	}
}

// 获取系统资源使用情况
static void Bm_function_Syscall_getrusage(benchmark::State &state)
{
	struct rusage usage;
	long result;
	for (auto _ : state)
	{
		result = syscall(SYS_getrusage, RUSAGE_SELF, &usage);
		benchmark::DoNotOptimize(result);
	}
	// 若获取到
	if (result == 0)
	{
		printf("system time: %ld.%06lds\n", usage.ru_utime.tv_sec, usage.ru_utime.tv_usec);
		printf("usertime: %ld.%06lds\n", usage.ru_stime.tv_sec, usage.ru_stime.tv_usec);
	}
	else
	{
		printf("error\n");
	}
}

// 获取系统信息
static void Bm_function_Syscall_uname(benchmark::State &state)
{
	struct utsname buf;
	long int ret;
	for (auto _ : state)
	{
		ret = syscall(SYS_uname, &buf);
		benchmark::DoNotOptimize(ret);
	}
	if (ret == 0)
	{
		printf("sysname%s\n", buf.sysname);
		printf("nodename%s\n", buf.nodename);
		printf("release%s\n", buf.release);
		printf("version%s\n", buf.version);
		printf("machine%s\n", buf.machine);
	}
	else
	{
		printf("error\n");
	}
}

MUSL_BENCHMARK(Bm_function_Syscall_getpid);
MUSL_BENCHMARK(Bm_function_Syscall_gettid);
MUSL_BENCHMARK(Bm_function_Syscall_gettimeofday);
MUSL_BENCHMARK(Bm_function_Syscall_write);
MUSL_BENCHMARK(Bm_function_Syscall_read);
MUSL_BENCHMARK(Bm_function_Syscall_fcntl);
MUSL_BENCHMARK(Bm_function_Syscall_getrusage);
MUSL_BENCHMARK(Bm_function_Syscall_uname);
